package com.flex.showdoc4j.reflection;

import org.springframework.beans.BeanUtils;
import org.springframework.util.Assert;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author ganlt<br>
 * @since 2019/06/26 14:50 <br>
 */
public class FieldReflection {

    public static Object getDescriptor(Object result, String searchName) {
        Assert.notNull(searchName, "搜索参数不能为空");
        if (result instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> map = (Map<String, Object>) result;
            return map.get(searchName);
        } else {
            PropertyDescriptor[] propertyDescriptors = BeanUtils.getPropertyDescriptors(result.getClass());
            for (PropertyDescriptor descriptor : propertyDescriptors) {
                String name = descriptor.getName();
                if (searchName.equalsIgnoreCase(name)) {
                    return getProperty(descriptor, result);
                }
            }
        }
        return null;
    }

    private static Object getProperty(PropertyDescriptor dp, Object obj) {
        //获取对象属性方法
        Method method = dp.getReadMethod();
        //获取属性对应的值
        Object retValue = null;
        try {
            retValue = method.invoke(obj);
        } catch (IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
        return retValue;
    }

    public static List<Field> getFields(Object result, boolean isSuper) {
        if (result instanceof List || result instanceof Set) {
            List<Field> resultList = ((List<Field>)result);
            result = resultList.get(0);
        }
        Class<?> superClass;
        if (result instanceof Class) {
            superClass =  ((Class<?>) result).getSuperclass();
        } else {
            superClass = result.getClass().getSuperclass();
        }
        Field[] superFields;
        if (isSuper) {
            superFields = superClass.getDeclaredFields();
        } else {
            superFields = new Field[]{};
        }
        Field[] fields;
        if (result instanceof Class) {
            fields =  ((Class<?>) result).getDeclaredFields();
        } else {
            fields = result.getClass().getDeclaredFields();
        }
        Field[] resultFields = new Field[superFields.length + fields.length];
        System.arraycopy(superFields, 0, resultFields, 0, superFields.length);
        System.arraycopy(fields, 0, resultFields, superFields.length, fields.length);

        List<Field> fieldList = Arrays.stream(resultFields).filter(filed -> !Modifier.isFinal(filed.getModifiers())).collect(Collectors.toList());

        return fieldList;
    }

    public static Object getValue(Field field, Object obj) {
        try {
            field.setAccessible(true);
            return field.get(obj);
        } catch (IllegalAccessException e) {
            return null;
        }

    }
}
